using System;
using System.Xml;
using System.Globalization;



namespace Waymex.Gps
{

	/// <summary>
	/// This object forms part of the FlightBookCollection which is returned by 
    /// the GetFlightBooks method of the GarminDevice object.
	/// </summary>
	/// <remarks>
    /// <para>Garmin Devices Only.</para>
	/// <para>
	/// In some cases not all of the Properties of the FlightBook object are used. The Properties
	/// actually used are determined by the protocol employed by the connected GPS Device.
	/// Below is a list of which Properties are supported by Protocol. Please note that even though a
	/// Property is identified as being supported does not mean that it will actually be used/populated.
	/// </para>
	/// <br/><br/>
	/// <para>
	/// <b>Protocol D500</b>
	/// </para>
	/// <list type="table">
	/// <listheader><term>Property</term><description>Type</description></listheader>
	/// <item><term>WeekNumber</term><description>Int32</description></item>
	/// <item><term>ReferenceTime</term><description>Single</description></item>
	/// <item><term>ClockCorrectionAF0</term><description>Single</description></item>
	/// <item><term>ClockCorrectionAF1</term><description>Single</description></item>
	/// <item><term>Eccentricity</term><description>Single</description></item>
	/// <item><term>SqrRootSemiMajorAxis</term><description>Single</description></item>
	/// <item><term>MeanAnomaly</term><description>Single</description></item>
	/// <item><term>Perigee</term><description>Single</description></item>
	/// <item><term>RightAscension</term><description>Single</description></item>
	/// <item><term>RightAscensionRate</term><description>Single</description></item>
	/// <item><term>Inclination</term><description>Single</description></item>
	/// </list>
	/// <para>
	/// The TakeoffTime and LandingTime properties are expressed as the
	/// number of seconds elapsed since UTC 24:00 December 31, 1989.
	/// </para>
	/// </remarks>
	public class FlightBook : DataObjectBase
	{
		private int m_hashCode = -1;

        private int m_takeoffTime = 0;
        private int m_landingTime = 0;
        private double m_takeoffLatitude = 0;
        private double m_takeoffLongitude = 0;
        private double m_landingLatitude = 0;
        private double m_landingLongitude = 0;
        private int m_nightTime = 0;
        private int m_numberOfLandings = 0;
        private float m_maximumSpeed = 0;
        private float m_maximumAltitude = 0;
        private float m_distance = 0;
        private bool m_crossCountry = false;
        private string m_departureName = "";
        private string m_departureIdentity = "";
        private string m_arrivalName = "";
        private string m_arrivalIdentity = "";
        private string m_aircraftId = "";

		/// <summary>
		/// Returns/Sets the TakeoffTime property of the Flight Book.
		/// </summary>
		public int TakeoffTime
        {
            get
            {
                return m_takeoffTime;
            }
            set
            {
                m_takeoffTime = value;
            }
        }
		/// <summary>
		/// Returns/Sets the LandingTime property of the Flight Book.
		/// </summary>
		public int LandingTime
        {
            get
            {
                return m_landingTime;
            }
            set
            {
                m_landingTime = value;
            }
        }
		/// <summary>
		/// Returns/Sets the TakeoffLatitude property of the Flight Book.
		/// </summary>
		public double TakeoffLatitude
        {
            get
            {
                return m_takeoffLatitude;
            }
            set
            {
                m_takeoffLatitude = value;
            }
        }
		/// <summary>
		/// Returns/Sets the TakeoffLongitude property of the Flight Book.
		/// </summary>
		public double TakeoffLongitude
        {
            get
            {
                return m_takeoffLongitude;
            }
            set
            {
                m_takeoffLongitude = value;
            }
        }
		/// <summary>
		/// Returns/Sets the LandingLatitude property of the Flight Book.
		/// </summary>
		public double LandingLatitude
        {
            get
            {
                return m_landingLatitude;
            }
            set
            {
                m_landingLatitude = value;
            }
        }
		/// <summary>
		/// Returns/Sets the LandingLongitude property of the Flight Book.
		/// </summary>
		public double LandingLongitude
        {
            get
            {
                return m_landingLongitude;
            }
            set
            {
                m_landingLongitude = value;
            }
        }
		/// <summary>
		/// Returns/Sets the NightTime property of the Flight Book.
		/// </summary>
		public int NightTime
        {
            get
            {
                return m_nightTime;
            }
            set
            {
                m_nightTime = value;
            }
        }
		/// <summary>
		/// Returns/Sets the NumberOfLandings property of the Flight Book.
		/// </summary>
		public int NumberOfLandings
        {
            get
            {
                return m_numberOfLandings;
            }
            set
            {
                m_numberOfLandings = value;
            }
        }
		/// <summary>
		/// Returns/Sets the MaximumSpeed property of the Flight Book.
		/// </summary>
		public float MaximumSpeed
        {
            get
            {
                return m_maximumSpeed;
            }
            set
            {
                m_maximumSpeed = value;
            }
        }
		/// <summary>
		/// Returns/Sets the MaximumAltitude property of the Flight Book.
		/// </summary>
		public float MaximumAltitude
        {
            get
            {
                return m_maximumAltitude;
            }
            set
            {
                m_maximumAltitude = value;
            }
        }
		/// <summary>
		/// Returns/Sets the Distance property of the Flight Book.
		/// </summary>
		public float Distance
        {
            get
            {
                return m_distance;
            }
            set
            {
                m_distance = value;
            }
        }
		/// <summary>
		/// Returns/Sets the CrossCountry property of the Flight Book.
		/// </summary>
		public bool CrossCountry
        {
            get
            {
                return m_crossCountry;
            }
            set
            {
                m_crossCountry = value;
            }
        }
		/// <summary>
		/// Returns/Sets the DepartureName property of the Flight Book.
		/// </summary>
		public string DepartureName
        {
            get
            {
                return m_departureName;
            }
            set
            {
                m_departureName = value;
            }
        }
		/// <summary>
		/// Returns/Sets the DepartureIdentity property of the Flight Book.
		/// </summary>
		public string DepartureIdentity
        {
            get
            {
                return m_departureIdentity;
            }
            set
            {
                m_departureIdentity = value;
            }
        }
		/// <summary>
		/// Returns/Sets the ArrivalName property of the Flight Book.
		/// </summary>
		public string ArrivalName
        {
            get
            {
                return m_arrivalName;
            }
            set
            {
                m_arrivalName = value;
            }
        }
		/// <summary>
		/// Returns/Sets the ArrivalIdentity property of the Flight Book.
		/// </summary>
		public string ArrivalIdentity
        {
            get
            {
                return m_arrivalIdentity;
            }
            set
            {
                m_arrivalIdentity = value;
            }
        }
		/// <summary>
		/// Returns/Sets the AircraftId property of the Flight Book.
		/// </summary>
		public string AircraftId
        {
            get
            {
                return m_aircraftId;
            }
            set
            {
                m_aircraftId = value;
            }
        }

		private const string XML_ROOT  = "gpsflightbook";
		private const string XML_TAKEOFF_TIME = "takeoff_time";
		private const string XML_LANDING_TIME = "landing_time";
		private const string XML_TAKEOFF_LATITUDE = "takeoff_latitude";
		private const string XML_TAKEOFF_LONGITUDE = "takeoff_longitude";
		private const string XML_LANDING_LATITUDE = "landing_latitude";
		private const string XML_LANDING_LONGITUDE = "landing_longitude";
		private const string XML_NIGHT_TIME = "night_time";
		private const string XML_NUMBER_OF_LANDINGS = "number_of_landings";
		private const string XML_MAXIMUM_SPEED = "maximum_speed";
		private const string XML_MAXIMUM_ALTITUDE = "maximum_altitude";
		private const string XML_DISTANCE = "distance";
		private const string XML_CROSSCOUNTRY = "crosscountry";
		private const string XML_DEPARTURE_NAME = "departure_name";
		private const string XML_DEPARTURE_IDENTITY = "departure_identity";
		private const string XML_ARRIVAL_NAME = "arrival_name";
		private const string XML_ARRIVAL_IDENTITY = "arrival_identity";
		private const string XML_AIRCRAFT_ID = "aircraft_id";

		/// <summary>
		/// Returns an XML representation of the object.
		/// </summary>
		public string ToXml()
		{
			XmlDocument objXMLDOM = new XmlDocument();

			XmlElement objRootNode = null;
			
			try
			{
				//create the root node
				objRootNode = objXMLDOM.CreateElement(XML_ROOT);
			
				//append the root node to the document
				objXMLDOM.AppendChild(objRootNode);

				//create the child nodes
				AddXMLNode(objRootNode, XML_TAKEOFF_TIME,TakeoffTime.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_LANDING_TIME,LandingTime.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_TAKEOFF_LATITUDE,TakeoffLatitude.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_TAKEOFF_LONGITUDE,TakeoffLongitude.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_LANDING_LATITUDE,LandingLatitude.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_LANDING_LONGITUDE,LandingLongitude.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_NIGHT_TIME,NightTime.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_NUMBER_OF_LANDINGS,NumberOfLandings.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_MAXIMUM_SPEED,MaximumSpeed.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_MAXIMUM_ALTITUDE,MaximumAltitude.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_DISTANCE,Distance.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_CROSSCOUNTRY,CrossCountry.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_DEPARTURE_NAME,DepartureName, true);
				AddXMLNode(objRootNode, XML_DEPARTURE_IDENTITY,DepartureIdentity, true);
				AddXMLNode(objRootNode, XML_ARRIVAL_NAME,ArrivalName, true);
				AddXMLNode(objRootNode, XML_ARRIVAL_IDENTITY,ArrivalIdentity, true);
				AddXMLNode(objRootNode, XML_AIRCRAFT_ID,AircraftId, true);

			}

			catch(Exception e)
			{
				throw new XmlException(e.Message, e);
			}

			return objXMLDOM.OuterXml;
		}

		/// <summary>
		/// This method populates the object from XML.
		/// </summary>
        public void XmlLoad(string xml)
		{
			string strXPathRoot = "";
			XmlDocument objDOM = new XmlDocument();

			try
			{
                objDOM.LoadXml(xml);

				if(objDOM.FirstChild.Name == XML_ROOT)
				{
					strXPathRoot = string.Concat("//" , XML_ROOT , "/");

					//need to ignore type conversion errors and missing xml elements
					TakeoffTime = ReadXMLNodeAsInteger(objDOM, string.Concat(strXPathRoot, XML_TAKEOFF_TIME));
					LandingTime = ReadXMLNodeAsInteger(objDOM, string.Concat(strXPathRoot, XML_LANDING_TIME));
					TakeoffLatitude = ReadXMLNodeAsDouble(objDOM, string.Concat(strXPathRoot, XML_TAKEOFF_LATITUDE));
					TakeoffLongitude = ReadXMLNodeAsDouble(objDOM, string.Concat(strXPathRoot, XML_TAKEOFF_LONGITUDE));
					LandingLatitude = ReadXMLNodeAsDouble(objDOM, string.Concat(strXPathRoot, XML_LANDING_LATITUDE));
					LandingLongitude = ReadXMLNodeAsDouble(objDOM, string.Concat(strXPathRoot, XML_LANDING_LONGITUDE));
					NightTime = ReadXMLNodeAsInteger(objDOM, string.Concat(strXPathRoot, XML_NIGHT_TIME));
					NumberOfLandings = ReadXMLNodeAsInteger(objDOM, string.Concat(strXPathRoot, XML_NUMBER_OF_LANDINGS));
					MaximumSpeed = ReadXMLNodeAsSingle(objDOM, string.Concat(strXPathRoot, XML_MAXIMUM_SPEED));
					MaximumAltitude = ReadXMLNodeAsSingle(objDOM, string.Concat(strXPathRoot, XML_MAXIMUM_ALTITUDE));
					Distance = ReadXMLNodeAsSingle(objDOM, string.Concat(strXPathRoot, XML_DISTANCE));
					CrossCountry = ReadXMLNodeAsBoolean(objDOM, string.Concat(strXPathRoot, XML_CROSSCOUNTRY));
					DepartureName = ReadXMLNodeAsString(objDOM, string.Concat(strXPathRoot, XML_DEPARTURE_NAME));
					DepartureIdentity = ReadXMLNodeAsString(objDOM, string.Concat(strXPathRoot, XML_DEPARTURE_IDENTITY));
					ArrivalName = ReadXMLNodeAsString(objDOM, string.Concat(strXPathRoot, XML_ARRIVAL_NAME));
					ArrivalIdentity = ReadXMLNodeAsString(objDOM, string.Concat(strXPathRoot, XML_ARRIVAL_IDENTITY));
					AircraftId = ReadXMLNodeAsString(objDOM, string.Concat(strXPathRoot, XML_AIRCRAFT_ID));

				}
			}
            catch (NullReferenceException e)
            {
				throw new XmlException(e.Message ,e);
			}

		}
        /// <summary>
        /// Overridden method. Returns true of the values of each
        /// of the properties are equal in value.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>boolean</returns>
        public override bool Equals(object obj)
		{
			try
			{
				//check the type first
				if(obj.GetType() != this.GetType() )
					return false;

				//cast it
				FlightBook objFlightBook = (FlightBook)obj;

				if( objFlightBook.AircraftId != AircraftId ) return false; 
				if( objFlightBook.ArrivalIdentity != ArrivalIdentity ) return false;
				if( objFlightBook.ArrivalName != ArrivalName ) return false;
				if( objFlightBook.CrossCountry != CrossCountry ) return false;
				if( objFlightBook.DepartureIdentity != DepartureIdentity ) return false;
				if( objFlightBook.DepartureName != DepartureName ) return false;
				if( objFlightBook.Distance != Distance ) return false;
				if( objFlightBook.LandingLatitude != LandingLatitude ) return false;
				if( objFlightBook.LandingLongitude != LandingLongitude ) return false;
				if( objFlightBook.LandingTime != LandingTime ) return false;
				if( objFlightBook.MaximumAltitude != MaximumAltitude ) return false;
				if( objFlightBook.MaximumSpeed != MaximumSpeed ) return false;
				if( objFlightBook.NightTime != NightTime ) return false;
				if( objFlightBook.NumberOfLandings != NumberOfLandings ) return false;
				if( objFlightBook.TakeoffLatitude != TakeoffLatitude ) return false;
				if( objFlightBook.TakeoffLongitude != TakeoffLongitude ) return false;
				if( objFlightBook.TakeoffTime != TakeoffTime ) return false;

			}
			catch
			{
				throw;
			}
			finally
			{
			}
			//if we get here all must be the same.
			return true;
		}
        /// <summary>
        /// Overridden function. Retrieves a value that indicates the hash code value for the object.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
		{
			//this value will be used for the overriden GetHashCode function and should
			//ensure that two object that are the same return the same Hash Code.
			//the hash code has to be imutable to is stored in a member variable.
			if( m_hashCode <= 0 )
				m_hashCode = TakeoffTime.GetHashCode() ^ LandingTime.GetHashCode();
	
			return m_hashCode;
		}

	}
}
